package com.winsdom.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.winsdom.context.BaseContext;
import com.winsdom.dto.CategoryTreeNodes;
import com.winsdom.dto.FeecategoryThreeNodes;
import com.winsdom.dto.expenditure.ExpenditureDto;
import com.winsdom.dto.expenditure.ExpenditureUpsertDTO;
import com.winsdom.entity.*;
import com.winsdom.exception.BusinessException;
import com.winsdom.mapper.*;
import com.winsdom.result.Result;
import com.winsdom.service.IExpenditureService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.winsdom.vo.expenditure.ExpenditureVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 费项表 服务实现类
 * </p>
 *
 * @author
 * @since 2025-05-12
 */
@Service
public class ExpenditureServiceImpl extends ServiceImpl<ExpenditureMapper, Expenditure> implements IExpenditureService {

    @Autowired
    private ExpenditureMapper expenditureMapper;
    @Autowired
    private FeeCategoryMapper feeCategoryMapper;
    @Autowired
    private FeeFormulaMapper feeFormulaMapper;
    @Autowired
    private FormulaMapper formulaMapper;
    @Autowired
    private BillingAssociationMapper billingAssociationMapper;
    @Override
    public List<ExpenditureVo> getExpenditureList(ExpenditureDto expenditureDto) {
        List<ExpenditureVo> list = expenditureMapper.selectListForParams2(expenditureDto);
        return list;
    }

    @Override
    public List<FeeCategory> getFeeCategoryList() {
        List<FeeCategory> feeCategories = feeCategoryMapper.selectList(new LambdaQueryWrapper<FeeCategory>().eq(FeeCategory::getHasExpenditure, 1));
        return feeCategories;
    }

    @Override
    public List<FeecategoryThreeNodes> getFeeCategoryNodes() {
        List<FeecategoryThreeNodes> feeCategoryNodes = expenditureMapper.selectForFeeCategoryNodes(0L);
        return feeCategoryNodes;
    }

    @Override
    @Transactional
    public Result addExpenditure(ExpenditureUpsertDTO dto) {
        List<Expenditure> expenditures = expenditureMapper.selectList(new LambdaQueryWrapper<Expenditure>().eq(Expenditure::getExpenditureName, dto.getExpenditure().getExpenditureName()));
        if (!expenditures.isEmpty()) {
            return Result.error("费用名称已存在!");
        }
        List<FeeFormula> formulas = feeFormulaMapper.selectList(new LambdaQueryWrapper<FeeFormula>().eq(FeeFormula::getExpenditureId, dto.getExpenditure().getExpenditureId())
                .eq(FeeFormula::getType, 1));
        if(formulas.size()>=10){
            return Result.error("一个费项最多允许10个公式！");
        }
        List<FeeFormula> prices = feeFormulaMapper.selectList(new LambdaQueryWrapper<FeeFormula>().eq(FeeFormula::getExpenditureId, dto.getExpenditure().getExpenditureId())
                .eq(FeeFormula::getType, 2));
        if(prices.size()>=20){
            return Result.error("一个费项最多允许20个单价！");
        }
        Expenditure expenditure = new Expenditure();
        BeanUtils.copyProperties(dto.getExpenditure(), expenditure);
        Integer userId = BaseContext.getCurrentId();
        expenditure.setUserId(Long.valueOf(userId));
        expenditure.setCreateTime(LocalDateTime.now());
        expenditure.setUpdateTime(LocalDateTime.now());
        expenditure.setStatus(1);
        expenditureMapper.insert(expenditure);

        for (Formula formula : dto.getFormulas()) {
            FeeFormula feeFormula = new FeeFormula();
            feeFormula.setFormulaName(formula.getFormulaName());
            feeFormula.setExpenditureId(expenditure.getExpenditureId());
            feeFormula.setType(1);
            feeFormulaMapper.insert(feeFormula);
        }
        for(BigDecimal price : dto.getPrices()){
            FeeFormula feeFormula = new FeeFormula();
            feeFormula.setPrice(price);
            feeFormula.setType(2);
            feeFormula.setExpenditureId(expenditure.getExpenditureId());
            feeFormulaMapper.insert(feeFormula);
        }

        FeeCategory feeCategory = feeCategoryMapper.selectById(expenditure.getFeeCategoryId());
        feeCategory.setHasExpenditure(1);
        feeCategoryMapper.updateById(feeCategory);
        return Result.success();
    }

    @Override
    public Result getFormula(Integer nature) {
        List<Formula> formulas = formulaMapper.selectList(new LambdaQueryWrapper<Formula>().eq(Formula::getType, nature));
        return Result.success(formulas);
    }

    @Override
    public Result showExpenditure(Integer expenditureId) {
        Expenditure expenditure = expenditureMapper.selectById(expenditureId);
        List<FeeFormula> formulaList = feeFormulaMapper.selectList(new LambdaQueryWrapper<FeeFormula>().eq(FeeFormula::getExpenditureId, expenditureId)
                .eq(FeeFormula::getType, 1));
        List<Formula> formulas=new ArrayList<>();
        for(FeeFormula feeFormula:formulaList){
            Formula formula=formulaMapper.selectOne(new LambdaQueryWrapper<Formula>().eq(Formula::getType,expenditure.getNature())
                    .eq(Formula::getFormulaName,feeFormula.getFormulaName()));
            formulas.add(formula);
        }
        List<FeeFormula> formulas1 = feeFormulaMapper.selectList(new LambdaQueryWrapper<FeeFormula>().eq(FeeFormula::getExpenditureId, expenditureId)
                .eq(FeeFormula::getType, 2));
        List<BigDecimal> prices = formulas1.stream().map(FeeFormula::getPrice).collect(Collectors.toList());
        HashMap map = new HashMap();
        map.put("formulas", formulas);
        map.put("prices", prices);
        return Result.success(map);
    }

    @Override
    public Result stopExpenditure(Integer expenditureId) {
        List<BillingAssociation> billingAssociations = billingAssociationMapper.selectList(new LambdaQueryWrapper<BillingAssociation>().eq(BillingAssociation::getExpenditureId, expenditureId));
        if(!billingAssociations.isEmpty()){
            return Result.error("楼盘已关联的费项不允许停用");
        }
        Expenditure expenditure = expenditureMapper.selectById(expenditureId);
        if(expenditure.getStatus()==0){
            return Result.success();
        }
        expenditure.setStatus(0);
        expenditure.setUpdateTime(LocalDateTime.now());
        expenditureMapper.updateById(expenditure);
        return Result.success();
    }

    @Override
    @Transactional
    public Result updateExpenditure(ExpenditureUpsertDTO dto) {
        Expenditure expenditure = new Expenditure();
        BeanUtils.copyProperties(dto.getExpenditure(),expenditure);
        Integer userId = BaseContext.getCurrentId();
        expenditure.setUserId(Long.valueOf(userId));
        expenditure.setUpdateTime(LocalDateTime.now());
        expenditureMapper.updateById(expenditure);

        feeFormulaMapper.delete(new QueryWrapper<FeeFormula>().eq("expenditure_id",expenditure.getExpenditureId()));

        for (Formula formula : dto.getFormulas()) {
            FeeFormula feeFormula = new FeeFormula();
            feeFormula.setFormulaName(formula.getFormulaName());
            feeFormula.setExpenditureId(expenditure.getExpenditureId());
            feeFormula.setType(1);
            feeFormulaMapper.insert(feeFormula);
        }
        for(BigDecimal price : dto.getPrices()){
            FeeFormula feeFormula = new FeeFormula();
            feeFormula.setPrice(price);
            feeFormula.setType(2);
            feeFormula.setExpenditureId(expenditure.getExpenditureId());
            feeFormulaMapper.insert(feeFormula);
        }

        Expenditure expenditure1 = expenditureMapper.selectById(expenditure.getExpenditureId());
        if(expenditure1.getFeeCategoryId()==dto.getExpenditure().getFeeCategoryId()){  //费项分类没有修改
            return Result.success();
        }
        List<Expenditure> expenditures = expenditureMapper.selectList(new LambdaQueryWrapper<Expenditure>().eq(Expenditure::getFeeCategoryId, expenditure1.getFeeCategoryId()));
        if(expenditures.size()>=2){
            return Result.success();
        }

        FeeCategory feeCategory = feeCategoryMapper.selectById(expenditure1.getFeeCategoryId());
        feeCategory.setHasExpenditure(0);
        feeCategoryMapper.updateById(feeCategory);

        FeeCategory feeCategory1 = feeCategoryMapper.selectById(dto.getExpenditure().getFeeCategoryId());
        feeCategory1.setHasExpenditure(1);
        feeCategoryMapper.updateById(feeCategory1);
        return Result.success();
    }

}
